$def with(query, title=None, sort='new', key='', limit=20, search=False, has_fulltext_only=True, url=None, layout='carousel')

$# Takes following parameters
$# * query (str) -- Any arbitrary Open Library search query, e.g. subject:"Textbooks"
$# * title (str) -- A title to show above the carousel (links to /search?q=query)
$# * sort (str) -- optional sort param defined within work_search.py `work_search`
$# * key (str) -- unique name of the carousel in analytics
$# * limit (int) -- initial number of books to pull
$# * search (bool) -- whether to include search within collection
$# * layout (str) -- layout type, default 'carousel', currently also supports 'grid'

$# Enable search within this query
$if search:
  <form action="/search" class="olform pagesearchbox">
    <input type="hidden" name="q" value="$query"/>
    $if has_fulltext_only:
      <input type="hidden" name="has_fulltext" value="true"/>
    <input type="text" placeholder="$_('Search collection')" name="q2"/>
    <input type="submit"/>
  </form>

$code:
  # Limit to just fields needed to render carousels
  params = { 'q': query, 'fields': 'key,title,subtitle,author_name,cover_i,ia,availability,id_project_gutenberg,id_project_runeberg,id_librivox,id_standard_ebooks,id_openstax' }
  # Don't need fields in the search UI url, since they don't do anything there
  url = url or "/search?" + urlencode({'q': query})
  if has_fulltext_only:
    params['has_fulltext'] = 'true'

  results = work_search(params, sort=sort, limit=limit, facet=False)
  books = [storage(b) for b in (results.get('docs', []))]
  load_more = {"url": "/search.json?" + urlencode(params), "limit": limit }

$:render_template("books/custom_carousel", books=books, title=title, url=url, key=key, load_more=load_more, layout=layout)
